

#include "xs_def.h"
#include "xs_linux.h"
#include "xs_log.h"

int xs_gettimeofday (struct timeval *__tv, struct timezone *__tz)
{
    return gettimeofday(__tv, __tz);
}

int xs_wait (unsigned short int __msec)
{
    timespec_t  __req_time__;

    if (__msec > 999) {/* more than 1 Sec */
        __req_time__.tv_sec  = __msec / 1000;
        __req_time__.tv_nsec = (__msec * 1000 * 1000) - ((__msec / 1000) * 1000 * 1000 * 1000);
	} else {
        __req_time__.tv_sec  = 0; /* Zero seconds */
        __req_time__.tv_nsec = (__msec * 1000 * 1000);
	}
	
    nanosleep (&__req_time__, NULL);
	
	return (EXIT_OK);
}

/*
*  xs_create_thread_with_arg () return thread id if successed,
*  zero returned when failure.
*/
unsigned long xs_pthread_create (void*(*__thread_func__)(void *), void  *__arg__)
{
    int __result__ = 0;
    unsigned long       __id__;
    xs_pthread_t        __thread__;

    __result__ = pthread_create(&(__thread__), NULL, __thread_func__, __arg__);
    if (__result__ != 0) {
        /* EINVAL, EAGAIN, EPERM maybe returned when execute failure */
        xs_loge ("%s", strerror (errno));
        __id__ = 0;
    } else {
        __id__ = (unsigned long)(__thread__);
	}

    return (__id__);
}

int xs_pthread_join ( xs_pthread_t __pid, void **retval)
{
    int __result__;

    __result__ =  pthread_join( __pid, retval );
    if(__result__ != 0){
        xs_loge("%s", strerror(errno));
        return EXIT_ERROR;
    }
    return EXIT_OK;
}
void xs_pthread_exit ( void )
{
    void *__return_param__ = NULL;
    pthread_exit(__return_param__);
}

int xs_pthread_attr_init(xs_pthread_attr_t *attr)
{
	int __result__;

	if(attr == NULL) return EXIT_ERROR;
	
	__result__ = pthread_attr_init(attr);
	if(__result__ != 0){
		xs_loge ("%s", strerror(errno));
        	return EXIT_ERROR;
	}

	return EXIT_OK;
}

int xs_pthread_attr_destroy(xs_pthread_attr_t *__attr)
{
	int __result__;

	if(__attr == NULL) return EXIT_ERROR;

	__result__ = pthread_attr_destroy(__attr);
	if(__result__ != 0){
		xs_loge ("%s", strerror(errno));
        	return EXIT_ERROR;
	}

	return EXIT_OK;
}

int xs_pthread_mutex_init (xs_pthread_mutex_t *__mutex,
                           const xs_pthread_mutex_attr_t *__mutex_attr)
{
    return ( (__mutex_attr == NULL) ?
            pthread_mutex_init(__mutex, NULL) :
            pthread_mutex_init(__mutex, __mutex_attr) );
}

int xs_pthread_mutex_lock (xs_pthread_mutex_t *__mutex)
{
    int __result__;

    if(__mutex == NULL) return EXIT_ERROR;

    __result__ = pthread_mutex_lock(__mutex);
    if(__result__ != 0) {
        if(errno == EINVAL) {
            ;   /* the mutex has not been properly initialized */
        }
        else if(errno == EDEADLK) {
            ;   /* the mutex is already locked by the calling thread */
        }
        xs_loge ("%s", strerror(errno));
        return EXIT_ERROR;
    }
    return EXIT_OK;
}

int xs_pthread_mutex_trylock (xs_pthread_mutex_t *__mutex)
{
    int __result__;

    if(__mutex == NULL) return EXIT_ERROR;

    __result__ = pthread_mutex_trylock(__mutex);
    if(__result__ != 0){
        if(errno == EBUSY) {
            ;   /* the mutex could not be acquired because it was currently locked. */
        }
        else if(errno == EINVAL) {
            ;   /* the mutex has not been properly initialized. */
        }
        xs_loge("%s", strerror(errno));
        return EXIT_ERROR;
    }
    return EXIT_OK;
}

int xs_pthread_mutex_unlock (xs_pthread_mutex_t *__mutex)
{
    int __result__;

    if(__mutex == NULL) return EXIT_ERROR;

    __result__ = pthread_mutex_unlock(__mutex);
    if(__result__ != 0) {
        if(errno == EINVAL) {
            ;   /* the mutex has not been properly initialized, invalid argument */
        }
        else if(errno == EPERM) {
            ;   /* the calling thread does not own the mutex, operation not permitted */
        }
        xs_loge("%s", strerror(errno));
        return EXIT_ERROR;
    }
    return EXIT_OK;
}

int xs_pthread_mutex_timedlock(xs_pthread_mutex_t *__mutex, const long __noseconds)
{
    int __result__;
    struct timeval __abs_timeout__;
    struct timezone __tz__;
    timespec_t __timeout__;

    if(__mutex == NULL) return EXIT_ERROR;

    /* Get current real time clock and add to it the waiting time */
    __timeout__.tv_sec  = 0;
    __timeout__.tv_nsec = 0;
    errno = 0; /* reset errno before error occurs */

    xs_gettimeofday(&__abs_timeout__, &__tz__);

    /* [mutex clock](sec) = [current clock](sec) + [user wait time, only sec] */
    __timeout__.tv_sec  = __abs_timeout__.tv_sec + (__noseconds / 1000);
    /* [mutex clock](nsec) = [current clock](nsec) + [user wait time, only milisec](nsec) */
    __timeout__.tv_nsec = (__abs_timeout__.tv_usec * 1000) + ((__noseconds % 1000) * 1000000);

    /* [current clock](nsec) + [user wait time, less then sec](nsec) > 1sec(nsec)*/
    if ((__timeout__.tv_nsec) > 1000000000) {
        /* we have more then 1 sec in nano sec so inc the sec */
        __timeout__.tv_sec  += 1;
        __timeout__.tv_nsec -= 1000000000;
    }

    __result__ = pthread_mutex_timedlock(__mutex, &__timeout__);
    if(__result__ != 0) {
        if (errno == ETIMEDOUT) {
            xs_loge("semaphore wait timeout");
            return (TIME_OUT);
        }else {
            xs_logd("%s", strerror (errno));
            return (EXIT_ERROR);
        }
    }
    return EXIT_OK;
}


int xs_pthread_mutex_destroy(xs_pthread_mutex_t *__mutex)
{
    int __result__;

    if(__mutex == NULL) return EXIT_ERROR;

    __result__ = pthread_mutex_destroy(__mutex);
    if(__result__ != 0) {
        if( errno == EBUSY) {
            ; /* the mutex is currently locked. */
        }
        xs_loge("%s", strerror(errno));
        return EXIT_ERROR;
    }
    return EXIT_OK;
}



/*
       EINTR:  The call was interrupted by a signal handler; see signal(7).

       EINVAL: sem is not a valid semaphore.


       The following additional error can occur for sem_trywait():

       EAGAIN: 
              The operation could not be performed without blocking (i.e., the semaphore currently has the value zero).


       The following additional errors can occur for sem_timedwait():

       EINVAL: 
       	 The value of abs_timeout.tv_nsecs is less than 0, or greater than or equal to 1000 million.

       ETIMEDOUT
              The call timed out before the semaphore could be locked.
*/
int xs_counting_semaphore_init ( xs_counting_semaphore_t  *__semaphore,
                                    const unsigned short int     __val )
{
    int __result__=0;

    errno = 0;

    __result__ = sem_init (__semaphore, 0, __val);
    if (__result__ == -1) {
        xs_loge ("%s", strerror (errno));
		return (EXIT_ERROR);
	}
	return (EXIT_OK);
}

int xs_counting_semaphore_post ( xs_counting_semaphore_t  *__semaphore )
{
    int __result__ = 0;

    errno = 0;

    __result__ = sem_post (__semaphore);
    if (__result__ == -1) {
        xs_logd ("%s", strerror (errno));
		return (EXIT_ERROR);
	}

	return (EXIT_OK);
}

/*
*  xs_counting_semaphore_wait()  decrements  (locks)  the semaphore pointed to by sem.  
*  If the semaphore's value is greater than zero, then the decrement
*  proceeds, and the function returns, immediately.  
*  If the semaphore currently has the value zero, then the call blocks  until  either
*  it becomes possible to perform the decrement (i.e., the semaphore value rises above zero), 
*  or a signal handler interrupts the call.
*/
int xs_counting_semaphore_wait ( xs_counting_semaphore_t  *__semaphore )
{
    int __result__ = 0;

    errno = 0;

    __result__ = sem_wait (__semaphore); /* Always return 0 */
    if (__result__ < 0) {
       xs_logd ("%s", strerror (errno));
	   return (EXIT_ERROR);
	}
	
	return (EXIT_OK);
}

/*
*  xs_counting_semaphore_trywait()  is  the  same as sem_wait(), except that if the decrement cannot be immediately performed, 
*  then call returns an error (errno set to EAGAIN) instead of blocking.
*/
int xs_counting_semaphore_trywait ( xs_counting_semaphore_t  *__semaphore )
{
    int __result__=0;

	errno = 0;

    __result__ = sem_trywait (__semaphore);
    if (__result__ == 0) {
        return (EXIT_OK);
    } else {
        /* EAGAIN: The operation could not be performed without blocking
        (i.e., the semaphore currently has the value zero). */
        if(errno == EAGAIN)
            return EXIT_OK;
        else {
            /*  something maybe wrong */
            xs_logd ("%s", strerror (errno));
            return (EXIT_ERROR);
        }
	}
}

/* 
*   xs_counting_semaphore_wait_timeout() is the same as sem_wait(), 
*   except that abs_timeout specifies a limit on the amount of  time  that  the  call  should
*   block  if  the decrement cannot be immediately performed. 
*/
int xs_counting_semaphore_timedwait ( xs_counting_semaphore_t    *__semaphore,
                                         long int                   __milliseconds
                                       )
{
    struct timeval __abs_timeout__;
    struct timezone __tz__;
    timespec_t __timeout__;
    short int  __result__;

	/* Get current real time clock and add to it the waiting time */
    __timeout__.tv_sec  = 0;
    __timeout__.tv_nsec = 0;
	errno = 0; /* reset errno before error occurs */

    xs_gettimeofday(&__abs_timeout__, &__tz__);

	/* [sem clock](sec) = [current clock](sec) + [user wait time, only sec] */
    __timeout__.tv_sec  = __abs_timeout__.tv_sec + (__milliseconds / 1000);
	/* [sem clock](nsec) = [current clock](nsec) + [user wait time, only milisec](nsec) */
    __timeout__.tv_nsec = (__abs_timeout__.tv_usec * 1000) + ((__milliseconds % 1000) * 1000000);

	/* [current clock](nsec) + [user wait time, less then sec](nsec) > 1sec(nsec)*/
    if ((__timeout__.tv_nsec) > 1000000000) {
		/* we have more then 1 sec in nano sec so inc the sec */
        __timeout__.tv_sec  += 1;
        __timeout__.tv_nsec -= 1000000000;
	}

    __result__ = sem_timedwait (__semaphore, &__timeout__);
    if (__result__ == 0) {
		/* semaphore was signalled */
		return (EXIT_OK);
    }else if (__result__ > 0) {
		/* buggy glibc, copy the returned error code to errno, 
		   where it should be */
        errno = __result__;
    }else {
		/* error code is in errno */
        if (errno == ETIMEDOUT) {
		    xs_loge("semaphore wait timeout");		
		    return (TIME_OUT);
		}
        else {
			xs_logd("%s", strerror (errno));
        }
        return (EXIT_ERROR);
	}

	return (EXIT_OK);
}

int xs_counting_semaphore_destroy ( xs_counting_semaphore_t  *__semaphore )
{
    int __result__=0;

	errno=0; 

    __result__ = sem_destroy (__semaphore);
    if (__result__ != 0) {
		xs_loge("%s", strerror (errno));
		return (EXIT_ERROR);
	}

	return (EXIT_OK);
}

int xs_pthread_cond_init(xs_pthread_cond_t *__cond, xs_pthread_cond_attr_t *__attr)
{
	int __result__;

	__result__ = ((__attr == NULL) ? pthread_cond_init(__cond, NULL) :
            				pthread_cond_init(__cond, __attr));
	if(__result__ != 0){
		xs_loge("%s", strerror (errno));
		return (EXIT_ERROR);
	}
	
	return EXIT_OK;
}

int xs_pthread_cond_signal(xs_pthread_cond_t *__cond)
{
	int __result__;

	if(__cond == NULL) return EXIT_ERROR;
	
	__result__ = pthread_cond_signal(__cond);
	if(__result__ != 0){
		xs_loge("%s", strerror (errno));
		return (EXIT_ERROR);
	}

	return EXIT_OK;
}

int xs_pthread_cond_broadcast(xs_pthread_cond_t *__cond)
{
	int __result__;

	if(__cond == NULL) return EXIT_ERROR;
	
	__result__ = pthread_cond_broadcast(__cond);
	if(__result__ != 0){
		xs_loge("%s", strerror (errno));
		return (EXIT_ERROR);
	}

	return EXIT_OK;
}

/**
	Atomically  unlocks  the __mutex (as per pthread_unlock_mutex) 
	and waits for the condition variable __cond to be signaled.
	
*/
int xs_pthread_cond_wait(xs_pthread_cond_t * __cond, xs_pthread_mutex_t *__mutex)
{
	int __result__;

	if( (__cond == NULL) || (__mutex == NULL) )  return (EXIT_ERROR);

	__result__ = pthread_cond_wait(__cond, __mutex);
	if(__result__ != 0){
		xs_loge("%s", strerror (errno));
		return (EXIT_ERROR);
	}
		
	return (EXIT_OK);
}

int xs_pthread_cond_timedwait(xs_pthread_cond_t *__cond, 
									xs_pthread_mutex_t *__mutex, 
									unsigned long __noseconds)
{
	int __result__;
	struct timeval __abs_timeout__;
	struct timezone __tz__;
	timespec_t __timeout__;

	if(__cond == NULL || __mutex == NULL) return EXIT_ERROR;

	/* Get current real time clock and add to it the waiting time */
	__timeout__.tv_sec  = 0;
	__timeout__.tv_nsec = 0;
	errno = 0; /* reset errno before error occurs */

	xs_gettimeofday(&__abs_timeout__,&__tz__);

	/* [mutex clock](sec) = [current clock](sec) + [user wait time, only sec] */
	__timeout__.tv_sec  = __abs_timeout__.tv_sec + (__noseconds / 1000);
	/* [mutex clock](nsec) = [current clock](nsec) + [user wait time, only milisec](nsec) */
	__timeout__.tv_nsec = (__abs_timeout__.tv_usec * 1000) + ((__noseconds % 1000) * 1000000);

	/* [current clock](nsec) + [user wait time, less then sec](nsec) > 1sec(nsec)*/
	if ((__timeout__.tv_nsec) > 1000000000) {
		/* we have more then 1 sec in nano sec so inc the sec */
		__timeout__.tv_sec  += 1;
		__timeout__.tv_nsec -= 1000000000;
	}

	__result__ = pthread_cond_timedwait(__cond, __mutex, &__timeout__);
	if(__result__ != 0) {
		if (errno == ETIMEDOUT) {
		    xs_loge("semaphore wait timeout");
		    return (TIME_OUT);
		}else {
		    xs_logd("%s", strerror (errno));
		    return (EXIT_ERROR);
		}
	}
	
	return EXIT_OK;
}

int xs_pthread_cond_destroy(xs_pthread_cond_t *__cond)
{
	int __result__;

	if(__cond == NULL) return (EXIT_ERROR);

	__result__ = pthread_cond_destroy(__cond);
	if(__result__ != 0){
		xs_loge("%s", strerror (errno));
		return (EXIT_ERROR);
	}

	return (EXIT_OK);
}

char *xs_getcwd ( char *__buf, int __len)
{
    char  *__result__;

    __result__ = getcwd(__buf, __len);
    if (__result__ == (void *)0)
		xs_logd("%s", strerror (errno));	
	
    return __result__;
}

int xs_getpagesize(void)
{
	return getpagesize();
}